﻿using System;
using System.Collections.Generic;
using System.Text;
using Com.Toook.ParseHtml.Entity;
using System.Xml;
using Com.Toook.Common;
using Com.Toook.ParseHtml.Enum;

namespace Com.Toook.ParseHtml
{
    public class CreateContentByXml
    {
        /// <summary>
        /// 网站的配置文件路径
        /// </summary>
        private string xmlPath = null;
        private DetailRoadMap detailRoadMap = new DetailRoadMap();
        /// <summary>
        /// 根据一个网站的配置文件，解析出内容路线图DetailRoadMap的Rule/Step/Property等对象
        /// </summary>
        /// <param name="xmlPath">网站的配置文件路径</param>
        public CreateContentByXml(string xmlPath)
        {
            this.xmlPath = xmlPath;
        }
        /// <summary>
        /// 获取详细内容的路线图规则DetailRoadMap
        /// </summary>
        /// <param name="kindId">详细内容detail节点的id名称</param>       
        /// <returns></returns>
        public DetailRoadMap GetDetailRoadMap(string detailId)
        {
            //根据kindId获取xml节点
            XmlNode detailNode = GetDetailNodeFromXml(detailId);
            detailRoadMap.InsertTableName = detailNode.Attributes["insertTable"].Value;
            detailRoadMap.SqlFields = detailNode.Attributes["sqlFields"].Value;

            //获取分类页面原始url            
            detailRoadMap.SiteKindId = detailId;

            SetTransferPageRuleList(detailNode);
            SetContentPageRule(detailNode);

            return detailRoadMap;
        }
        /// <summary>
        /// 设置中间页面的跳转解析规则
        /// </summary>
        /// <param name="detailNode"></param>
        private void SetTransferPageRuleList(XmlNode detailNode)
        {
            XmlNodeList transferNodes = detailNode.SelectNodes("transferPage");
            if (transferNodes.Count > 0)//detailNode.SelectNodes("不存在的名称") 时不会返回null，不用判断transferNodes != null && 
            {
                List<TransferPage> transferList = new List<TransferPage>(transferNodes.Count);
                
                foreach (XmlNode transferNode in transferNodes)
                {
                    XmlNodeList ruleNodes = transferNode.SelectNodes("rule");
                    List<Rule> ruleList = ParseRuleList(ruleNodes);
                    TransferPage page = new TransferPage();

                    page.Rule = ruleList[0];//跳转页面只有一个规则
                    page.InitStep = ParseStep(transferNode.SelectSingleNode("initElements"));
                    transferList.Add(page);
                }

                detailRoadMap.transferPageList = transferList;
            }
        }
        /// <summary>
        /// 设置内容页面的解析规则
        /// </summary>
        /// <param name="detailNode"></param>
        private void SetContentPageRule(XmlNode detailNode)
        {
            //只有一个最终的内容页面
            XmlNode contentNode = detailNode.SelectSingleNode("contentPage");            
            XmlNodeList steps = contentNode.SelectNodes("rule/step");
            XmlNodeList properties = contentNode.SelectNodes("rule/property");
            
            Rule rule = ParseRule(steps, properties);

            detailRoadMap.contentPage.InitStep = ParseStep(contentNode.SelectSingleNode("initElements")); 
            detailRoadMap.contentPage.rule = rule;
            XmlNode pageRules = contentNode.SelectSingleNode("pageRules");
            if (pageRules != null && pageRules.HasChildNodes)
            {
                detailRoadMap.contentPage.PageRuleList = InitPageRule(pageRules);
            }         
        }
        /// <summary>
        /// 如果分类有多个分页，解析出分页规则(如电影分类)
        /// </summary>
        /// <param name="pageNode"></param>
        private List<PageRule> InitPageRule(XmlNode pageRulesNode)
        {
            List<PageRule> pageRuleList = new List<PageRule>();
            XmlNodeList pageRules = pageRulesNode.SelectNodes("pageRule");
            foreach (XmlNode pageNode in pageRules)
            {
                PageRule pageRule = new PageRule();
                try
                {
                    pageRule.PageType = (PageType)System.Enum.Parse(typeof(PageType), pageNode.Attributes["type"].Value, true);
                }
                catch (Exception ex)
                {
                    LogHelper.Log.Error("InitPageRule() 分页type错误。type=" + pageNode.Attributes["type"].Value, ex);
                }
                //全部根据Rule直接获取下一页Url，不用判断分页类型                
                //if (pageRule.PageType == PageType.NextPageRule)                
                XmlNodeList stepNodes = pageNode.SelectNodes("step");
                XmlNodeList propNodes = pageNode.SelectNodes("property");
                if (stepNodes.Count > 0)
                {
                    foreach (XmlNode node in stepNodes)
                    {
                        Step step = ParseStep(node);
                        pageRule.NextPageRule.AddStep(step);
                    }
                }
                if (propNodes.Count > 0)
                {
                    foreach (XmlNode node in propNodes)
                    {
                        Property prop = ParseProperty(node);
                        pageRule.NextPageRule.AddProperty(prop);
                    }
                }

                pageRuleList.Add(pageRule);
            }
            return pageRuleList;
        }

        /// <summary>
        /// 获取配置文件中指定分类的XmlNode节点
        /// </summary>
        /// <returns></returns>
        private XmlNode GetDetailNodeFromXml(string detailId)//, out string detailUrl
        {
            XmlDocument docXml = new XmlDocument();
            docXml.Load(this.xmlPath);
            XmlElement root = docXml.DocumentElement;

            XmlNodeList detailNodes = root.SelectNodes("detail");
            foreach (XmlNode detail in detailNodes)
            {
                if (detailId == detail.Attributes["id"].Value)
                {
                    //return detail;
                    if (detail.Attributes["ref"] == null)//没有引用其他detail,自身定义了规则
                    {
                        //detailUrl = detail.Attributes["url"].Value;
                        return detail;
                    }
                    else//引用其他detail的规则
                    {
                        string refId = detail.Attributes["ref"].Value;
                        foreach (XmlNode d in detailNodes)
                        {
                            if (refId == d.Attributes["id"].Value)
                            {
                                //detailUrl = d.Attributes["url"].Value;
                                return d;
                            }
                        }
                    }
                }
            }

            LogHelper.Log.Error("指定的detailId=" + detailId + "不存在。" + this.xmlPath);
            throw new Exception("指定的detailId=" + detailId + "不存在。" + this.xmlPath);
        }

        /// <summary>
        /// 将分类中的每个规则rule解析为对应的 ruleList
        /// </summary>
        /// <param name="rules">一个分类kind下的多个rule节点</param>
        /// <returns></returns>
        private List<Rule> ParseRuleList(XmlNodeList rules)
        {
            List<Rule> ruleList = new List<Rule>(rules.Count);//一个分类可能有多个解析规则

            foreach (XmlNode ruleNode in rules)
            {
                XmlNodeList steps = ruleNode.SelectNodes("step"); //获取step节点
                XmlNodeList propertys = ruleNode.SelectNodes("property");
                Rule rule = ParseRule(steps, propertys);
                //rule.EntityName = ruleNode.Attributes["entity"].Value;//设置实体名称
                ruleList.Add(rule);
            }

            return ruleList;
        }
        /// <summary>
        /// 解析出每个Step和propertys,添加到Rule
        /// </summary>
        /// <param name="steps"></param>
        /// <returns></returns>
        private Rule ParseRule(XmlNodeList steps, XmlNodeList propertys)
        {
            Rule rule = new Rule();//一个规则rule对应一个StepList  
            if (steps != null)
            {
                foreach (XmlNode stepNode in steps)
                {
                    Step step = ParseStep(stepNode);//将xml中的每个step节点解析为Step对象
                    rule.AddStep(step);
                }
            }
            foreach (XmlNode propertyNode in propertys)
            {
                Property property = ParseProperty(propertyNode);//将xml中的每个property节点解析为Property对象
                rule.AddProperty(property);
            }

            return rule;
        }
        /// <summary>
        /// 解析实体的一个属性
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        private Property ParseProperty(XmlNode node)
        {
            XmlNodeList steps = node.SelectNodes("step");
            XmlNode result = node.SelectSingleNode("result");

            Property property = new Property();
            property.PropertyName = node.Attributes["name"].Value;
            if (node.Attributes["hasMultiUrl"] != null && node.Attributes["hasMultiUrl"].Value.ToLower() == "yes")
            {
                property.IsLastTransferHasMultiUrl = true;
            }
            if (steps != null)//添加结果的解析步骤
            {
                foreach (XmlNode stepNode in steps)
                {
                    Step step = ParseStep(stepNode);//将xml中的每个step节点解析为Step对象
                    property.AddStep(step);//添加属性的step解析步骤
                }
            }
            //添加获取结果的规则
            property.Result = new XmlResult();
            string getBy = result.Attributes["getBy"].Value;
            try
            {
                property.Result.GetBy = (GetBy)System.Enum.Parse(typeof(GetBy), getBy, true);
            }
            catch (Exception ex)
            {
                LogHelper.Log.Error("ParseProperty() getBy=" + getBy + "不合法, 文件：" + this.xmlPath, ex);
            }
            property.Result.Name = result.Attributes["name"].Value;
            XmlNode value = node.SelectSingleNode("value");
            property.Result.Value = value == null ? "" : value.InnerText;
            property.Result.ResultFilter = ParseFilter(result);
            return property;
        }
        /// <summary>
        /// 将xml中的每个step节点解析为Step对象
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        private Step ParseStep(XmlNode node)
        {
            Step step = new Step();
            string getBy = node.Attributes["getBy"].Value;
            step.Name = node.Attributes["name"].Value;
            XmlNode value = node.SelectSingleNode("value");
            step.Value = value == null ? "" : value.InnerText;

            step.FilterList = ParseFilter(node);

            try
            {
                step.GetBy = (GetBy)System.Enum.Parse(typeof(GetBy), getBy, true);
            }
            catch (Exception ex)
            {
                LogHelper.Log.Error("ParseStep() getBy=" + getBy + "不合法, 文件：" + this.xmlPath, ex);
            }

            return step;
        }
        /// <summary>
        /// 解析过滤规则
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        private List<Filter> ParseFilter(XmlNode node)
        {
            List<Filter> filterList = new List<Filter>();
            Filter filter = null;
            XmlNodeList filterNodes = node.SelectNodes("filter");
            if (filterNodes != null)
            {
                foreach (XmlNode f in filterNodes)
                {
                    filter = new Filter();
                    //string filterType = f.Attributes["type"].Value;
                    //try
                    //{
                    //    filter.FilterType = (FilterType)System.Enum.Parse(typeof(FilterType), filterType, true);
                    //}
                    //catch (Exception ex)
                    //{
                    //    LogHelper.Log.Error("ParseFilter() FilterType=" + filterType + "不合法, 文件：" + this.xmlPath, ex);
                    //}
                    string getBy = f.Attributes["getBy"].Value;
                    filter.Name = f.Attributes["name"].Value;
                    XmlNode value = f.SelectSingleNode("value");
                    filter.Value = value == null ? "" : value.InnerText;

                    try
                    {
                        filter.GetBy = (GetBy)System.Enum.Parse(typeof(GetBy), getBy, true);
                    }
                    catch (Exception ex)
                    {
                        LogHelper.Log.Error("ParseFilter() getBy=" + getBy + "不合法, 文件：" + this.xmlPath, ex);
                    }

                    filterList.Add(filter);
                }
            }

            return filterList;
        }
    }
}
